package sfs

import (
	"fmt"
)

// 二进制转对象

type IDataSerializer interface {
	Binary2object([]byte) (*TSfsObject, error)
	Binary2array([]byte) (*TSfsArray, error)
}

type DefaultSFSDataSerializer struct {
}

func NewDefaultSFSDataSerializer() IDataSerializer {
	return &DefaultSFSDataSerializer{}
}

func (d *DefaultSFSDataSerializer) Binary2object(data []byte) (*TSfsObject, error) {
	reader := NewBinaryReader(data, uint32(len(data)))
	return d.bin2object(reader, false)
}

func (d *DefaultSFSDataSerializer) bin2object(reader IBinaryReader, headreaded bool) (*TSfsObject, error) {
	if !headreaded {
		headbyte, err := reader.ReadUByte()
		if err != nil || headbyte != SfsObject {
			return nil, fmt.Errorf("invalid sfs data type. expected:%v, foud:%v", SfsObject, headbyte)
		}
	}
	size, _ := reader.ReadUShort()
	if size < 0 {
		return nil, fmt.Errorf("can't decode sfs data. size is negative:%v", size)
	}
	rs := &TSfsObject{Data: map[string]DataWrapper{}}
	for i := uint16(0); i < size; i++ {
		key, _ := reader.ReadUTF()
		rs.Data[key] = d.decodeObject(reader)
	}
	return rs, nil
}

func (d *DefaultSFSDataSerializer) Binary2array(data []byte) (*TSfsArray, error) {
	reader := NewBinaryReader(data, uint32(len(data)))
	return d.bin2array(reader, false)
}

func (d *DefaultSFSDataSerializer) bin2array(reader IBinaryReader, headreaded bool) (*TSfsArray, error) {
	if !headreaded {
		headbyte, err := reader.ReadUByte()
		if err != nil || headbyte != SfsArray {
			return nil, fmt.Errorf("invalid sfs data type. expected:%v, foud:%v", SfsArray, headbyte)
		}
	}
	size, _ := reader.ReadUShort()
	if size < 0 {
		return nil, fmt.Errorf("can't decode SFSArray data. size is negative:%v", size)
	}
	rs := &TSfsArray{Data: []DataWrapper{}}
	for i := uint16(0); i < size; i++ {
		rs.Data = append(rs.Data, d.decodeObject(reader))
	}
	return rs, nil
}

func (d *DefaultSFSDataSerializer) decodeObject(reader IBinaryReader) DataWrapper {
	headbyte, _ := reader.ReadUByte()
	switch headbyte {
	//case gmsg.Null:
	//	return &gmsg.DataWrapper{DataType: gmsg.Null, Data: nil}
	case Bool:
		b, _ := reader.ReadBool()
		return DataWrapper{DataType: Bool, Data: b}
	case Byte:
		b, _ := reader.ReadUByte()
		return DataWrapper{DataType: Byte, Data: b}
	case Short:
		b, _ := reader.ReadUShort()
		return DataWrapper{DataType: Short, Data: b}
	case Int:
		b, _ := reader.ReadUInt()
		return DataWrapper{DataType: Int, Data: b}
	case Long:
		b, _ := reader.ReadLong()
		return DataWrapper{DataType: Long, Data: b}
	case Float:
		b, _ := reader.ReadFloat()
		return DataWrapper{DataType: Float, Data: b}
	case Double:
		b, _ := reader.ReadDouble()
		return DataWrapper{DataType: Double, Data: b}
	case UtfString:
		b, _ := reader.ReadUTF()
		return DataWrapper{DataType: UtfString, Data: b}
	case BoolArray:
		size, _ := reader.ReadUShort()
		var op []bool
		for i := uint16(0); i < size; i++ {
			b, _ := reader.ReadBool()
			op = append(op, b)
		}
		return DataWrapper{DataType: BoolArray, Data: op}
	case ShortArray:
		size, _ := reader.ReadUShort()
		var op []uint16
		for i := uint16(0); i < size; i++ {
			b, _ := reader.ReadUShort()
			op = append(op, b)
		}
		return DataWrapper{DataType: ShortArray, Data: op}
	case IntArray:
		size, _ := reader.ReadUShort()
		var op []int32
		for i := uint16(0); i < size; i++ {
			b, _ := reader.ReadInt()
			op = append(op, b)
		}
		return DataWrapper{DataType: IntArray, Data: op}
	case LongArray:
		size, _ := reader.ReadUShort()
		var op []int64
		for i := uint16(0); i < size; i++ {
			b, _ := reader.ReadLong()
			op = append(op, b)
		}
		return DataWrapper{DataType: LongArray, Data: op}
	case DoubleArray:
		size, _ := reader.ReadUShort()
		var op []float64
		for i := uint16(0); i < size; i++ {
			b, _ := reader.ReadDouble()
			op = append(op, b)
		}
		return DataWrapper{DataType: DoubleArray, Data: op}
	case UtfStringArray:
		size, _ := reader.ReadUShort()
		var op []string
		for i := uint16(0); i < size; i++ {
			b, _ := reader.ReadUTF()
			op = append(op, b)
		}
		return DataWrapper{DataType: UtfStringArray, Data: op}
	case SfsArray:
		//b, _ := reader.ReadBytes(reader.BytesAvailable())
		tsfsArr, e := d.bin2array(reader, true)
		if e != nil {
			return DataWrapper{}
		}
		return DataWrapper{DataType: SfsArray, Data: tsfsArr}
	case SfsObject:
		//b, _ := reader.ReadBytes(reader.BytesAvailable())
		tsfsObj, e := d.bin2object(reader, true)
		if e != nil {
			return DataWrapper{}
		}
		return DataWrapper{DataType: SfsObject, Data: tsfsObj}
	default:
		return DataWrapper{}
	}
}
